package security

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"
	"time"
)

// SecurityConfig 保存安全配置
type SecurityConfig struct {
	AppID     string // 应用ID
	AppSecret string // 应用密钥
}

// Verifier 安全验证接口
type Verifier interface {
	// VerifyGatewayRequest 验证来自API网关的请求
	VerifyGatewayRequest(request *http.Request) (bool, error)

	// SignComponentRequest 为组件请求签名
	SignComponentRequest(request *http.Request) error

	// GetAppID 获取应用ID
	GetAppID() string
}

// DefaultVerifier 实现Verifier接口
type DefaultVerifier struct {
	appID     string
	appSecret string
}

// NewVerifier 创建新的安全验证器
func NewVerifier(appID, appSecret string) Verifier {
	return &DefaultVerifier{
		appID:     appID,
		appSecret: appSecret,
	}
}

// NewVerifierWithConfig 使用配置创建验证器
func NewVerifierWithConfig(config *SecurityConfig) Verifier {
	return &DefaultVerifier{
		appID:     config.AppID,
		appSecret: config.AppSecret,
	}
}

// GetAppID 获取应用ID
func (v *DefaultVerifier) GetAppID() string {
	return v.appID
}

// VerifyGatewayRequest 验证来自API网关的请求
func (v *DefaultVerifier) VerifyGatewayRequest(r *http.Request) (bool, error) {
	// 获取必要的请求头
	gatewayID := r.Header.Get("X-Gateway-ID")
	timestamp := r.Header.Get("X-Gateway-Timestamp")
	signature := r.Header.Get("X-Gateway-Signature")

	// 验证必要的请求头
	if gatewayID == "" || timestamp == "" || signature == "" {
		return false, fmt.Errorf("缺少必要的网关请求头")
	}

	// 检查时间戳是否在允许的时间窗口内（5分钟）
	ts, err := strconv.ParseInt(timestamp, 10, 64)
	if err != nil {
		return false, fmt.Errorf("无效的时间戳: %w", err)
	}

	now := time.Now().Unix()
	if now-ts > 300 || ts-now > 300 {
		return false, fmt.Errorf("时间戳超出允许的时间窗口")
	}

	// 获取原始客户端ID（如果存在）
	clientID := r.Header.Get("X-Client-AppID")

	// 读取请求体
	bodyBytes, err := io.ReadAll(r.Body)
	if err != nil {
		return false, fmt.Errorf("读取请求体失败: %w", err)
	}

	// 重新设置请求体，因为读取是破坏性的
	r.Body = io.NopCloser(strings.NewReader(string(bodyBytes)))

	// 构建签名字符串: {HTTP方法}|{请求路径}|{时间戳}|{客户端AppID}|{转发标记}|{请求体}
	signatureStr := fmt.Sprintf("%s|%s|%s|%s|%s|%s",
		r.Method,
		r.URL.Path,
		timestamp,
		clientID,
		"true", // 转发标记始终为true
		string(bodyBytes))

	// 计算预期的签名
	expectedSignature := calculateHMAC(signatureStr, v.appSecret)

	// 在开发阶段，API网关可能发送占位符签名
	if signature == "bypass-verification-placeholder" {
		// 临时模式，API网关未启用验签
		return true, nil
	}

	// 比较签名
	return signature == expectedSignature, nil
}

// SignComponentRequest 为组件请求签名
func (v *DefaultVerifier) SignComponentRequest(r *http.Request) error {
	// 添加组件请求头 - 严格按照接口文档中的请求头设置
	r.Header.Set("X-Component-AppID", v.appID)

	// 仅当API网关启用验签时才添加以下请求头
	// 目前根据接口文档，仅需要X-Component-AppID请求头

	return nil
}

// calculateHMAC 计算HMAC-SHA256
func calculateHMAC(data, secret string) string {
	h := hmac.New(sha256.New, []byte(secret))
	h.Write([]byte(data))
	return hex.EncodeToString(h.Sum(nil))
}
